package util

import (
	"context"
	"fmt"
	"github.com/chromedp/cdproto/network"
	"github.com/chromedp/chromedp"
	"log"
	"mp4/entity"
	"strings"
	"time"
)

const (
	M3u8_Sleep_Value = 90 * time.Second
)

func SwitchChooseM3u8(config entity.DownloadEntity, url string) entity.ResponseEntity {
	if strings.HasSuffix(url, config.AudioFileType) {
		index := strings.Index(url, "?")
		if index > 0 {
			length := len(url)
			val := url[index+1 : length]

			index = strings.Index(val, "=")
			length = len(val)
			if index > 0 {
				val = val[index+1 : length]
			}
			return entity.ResponseEntity{M3u8: val}
		}

		return entity.ResponseEntity{M3u8: url}
	}
	options := []chromedp.ExecAllocatorOption{
		//chromedp.Flag("blink-settings", "imagesEnabled=false"),
		chromedp.Flag("no-default-browser-check", true),
		chromedp.Flag("headless", true),
		chromedp.Flag("hide-scrollbars", true),
		chromedp.Flag("mute-audio", true),

		chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
	}
	options = append(chromedp.DefaultExecAllocatorOptions[:], options...)
	//创建chrome窗口
	allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
	defer cancel()
	allocCtx, _ = context.WithTimeout(allocCtx, M3u8_Sleep_Value)
	ctx, cancel := chromedp.NewContext(allocCtx)

	tsURL, m3u8, tsHeadURLMap, headerMap, _, cookies := SwitchChromedpTag(ctx, config, url)
	var tsURLS []string
	tsURLS = append(tsURLS, tsURL)
	return entity.ResponseEntity{TsURL: tsURL, M3u8: m3u8, TsHeads: tsHeadURLMap, TsURLs: tsURLS, Heads: headerMap, Cokies: cookies}
}

func SwitchChromedpTag(ctx context.Context, config entity.DownloadEntity, url string) (string, string, map[string]string, map[string]string,
	[]string, []*network.Cookie) {
	var bodyStr string
	var tsURL string
	var m3u8 string
	var cookies []*network.Cookie

	httpPlayEntity := initHttpPlay()

	chromedp.ListenTarget(ctx, func(ev interface{}) {
		switch evn := ev.(type) {
		case *network.EventRequestWillBeSent:
			httpPlayEntity = chooseEventRequestWillBeSent(evn, config, httpPlayEntity)
		case *network.EventLoadingFinished:
			httpPlayEntity = chooseEventLoadingFinished(evn, httpPlayEntity)
		case *network.EventResponseReceivedExtraInfo:
			httpPlayEntity = chooseEventResponseReceivedExtraInfo(evn, config, httpPlayEntity)
		}

		if evn, ok := ev.(*network.EventResponseReceived); ok {
			if evn.RequestID == httpPlayEntity.RequestIdOfM3u8 {
				//getResource(evn, config, headURL)
			}
		}
	})

	var actionErr error

	chromedp.Run(ctx,
		chromedp.Navigate(url),
		chromedp.Sleep(M3u8_Sleep_Value),
		chromedp.OuterHTML(`body`, &bodyStr, chromedp.ByQuery),
		chromedp.ActionFunc(func(ctx context.Context) error {
			cookies, actionErr = network.GetCookies().Do(ctx)
			return actionErr
		}),
	)

	m3u8 = cambM3u8(httpPlayEntity, config)
	for i := 0; i < 100; i++ {

		if !IsEmpty(m3u8) {
			break
		}
		log.Println("m3u8 is null; ", i, url)
		time.Sleep(1 * time.Second)
		m3u8 = cambM3u8(httpPlayEntity, config)
	}

	return tsURL, m3u8, httpPlayEntity.TsHeadURLMap, httpPlayEntity.HeadURLMap[m3u8], httpPlayEntity.Urls, cookies
}

func chooseHead(head network.Headers) map[string]string {
	headMap := make(map[string]string)
	length := len(head)
	if length > 0 {
		for key, value := range head {
			valueStr := fmt.Sprintf("%s", value)
			//if util.IsNotEmpty(valueStr) {
			headMap[key] = valueStr
			//}

		}
	}

	return headMap
}

func chooseEventRequestWillBeSent(evn *network.EventRequestWillBeSent, config entity.DownloadEntity, httpPlay entity.HttpPlayEntity) entity.HttpPlayEntity {

	if strings.Index(strings.ToLower(evn.Request.URL), strings.ToLower(config.AudioFileType)) > 0 {
		urlCharIndex := strings.Index(evn.Request.URL, "url=")
		if urlCharIndex == -1 {
			httpPlay.RequestIdOfM3u8 = evn.RequestID
			httpPlay.UrlMap[evn.RequestID] = evn.Request.URL
			headMap := chooseHead(evn.Request.Headers)
			httpPlay.HeadURLMap[evn.Request.URL] = headMap
			httpPlay.RequestIDs = append(httpPlay.RequestIDs, evn.RequestID)
		} else if urlCharIndex > 0 {
			len := len(evn.Request.URL)
			url := evn.Request.URL[urlCharIndex+4 : len]
			httpPlay.RequestIdOfM3u8 = evn.RequestID
			httpPlay.UrlMap[evn.RequestID] = url
			headMap := chooseHead(evn.Request.Headers)
			httpPlay.HeadURLMap[url] = headMap
			httpPlay.RequestIDs = append(httpPlay.RequestIDs, evn.RequestID)
		}

	} else if strings.Index(strings.ToLower(evn.Request.URL), strings.ToLower(config.AudioChildType)) > 0 {
		httpPlay.RequestIdOfTsURL = evn.RequestID
		httpPlay.TsURL = evn.Request.URL
		httpPlay.TsHeadURLMap = chooseHead(evn.Request.Headers)

	}
	httpPlay.RequestIdAndURL[evn.RequestID] = httpPlay.TsURL

	return httpPlay

}

func chooseEventLoadingFinished(evn *network.EventLoadingFinished, httpPlay entity.HttpPlayEntity) entity.HttpPlayEntity {
	url := httpPlay.UrlMap[evn.RequestID]

	if IsNotEmpty(url) {
		if httpPlay.Length < evn.EncodedDataLength {
			httpPlay.Length = evn.EncodedDataLength
		}

		httpPlay.LengthMap[evn.EncodedDataLength] = evn.RequestID
	}
	for i := 0; i < len(httpPlay.RequestIDs); i++ {
		if httpPlay.RequestIDs[i] == evn.RequestID {
			httpPlay.RequestIDs = append(httpPlay.RequestIDs[:i], httpPlay.RequestIDs[i+1:]...)
		}
	}
	return httpPlay
}

func chooseEventResponseReceivedExtraInfo(evn *network.EventResponseReceivedExtraInfo, config entity.DownloadEntity, httpPlay entity.HttpPlayEntity) entity.HttpPlayEntity {
	if len(config.ContentTypes) > 0 {
		ct := fmt.Sprint(evn.Headers["Content-Type"])
		for _, contentType := range config.ContentTypes {
			if strings.Index(ct, contentType) > -1 {
				httpPlay.ExtraInfoRequestIDs = append(httpPlay.ExtraInfoRequestIDs, evn.RequestID)
			}
		}
	}

	return httpPlay
}

func initHttpPlay() entity.HttpPlayEntity {
	var requestIdOfM3u8 network.RequestID
	var requestIdOfTsURL network.RequestID
	var tsURL string
	var urlMap = make(map[network.RequestID]string)
	var headURLMap = make(map[string]map[string]string)
	var tsHeadURLMap = make(map[string]string)
	var requestIdAndURL = make(map[network.RequestID]string)
	var lengthMap = make(map[float64]network.RequestID)
	var urls []string
	var requestIDs []network.RequestID
	var extraInfoRequestIDs []network.RequestID

	return entity.HttpPlayEntity{RequestIdOfM3u8: requestIdOfM3u8, RequestIdOfTsURL: requestIdOfTsURL,
		TsURL: tsURL, UrlMap: urlMap, HeadURLMap: headURLMap, TsHeadURLMap: tsHeadURLMap,
		RequestIdAndURL: requestIdAndURL, Urls: urls, LengthMap: lengthMap, RequestIDs: requestIDs, ExtraInfoRequestIDs: extraInfoRequestIDs}
}
func cambM3u8(httpPlayEntity entity.HttpPlayEntity, config entity.DownloadEntity) string {
	m3u8 := ""
	m3u8 = httpPlayEntity.UrlMap[httpPlayEntity.LengthMap[httpPlayEntity.Length]]
	if IsNotEmpty(m3u8) {
		return m3u8
	}

	m3u8 = httpPlayEntity.UrlMap[httpPlayEntity.RequestIdOfM3u8]
	if IsNotEmpty(m3u8) {
		return m3u8
	}

	if len(config.SourcceM3u8s) > 0 {
		for key := range httpPlayEntity.UrlMap {
			for _, m3 := range config.SourcceM3u8s {
				if strings.Index(httpPlayEntity.UrlMap[key], m3) > -1 {
					if IsNotEmpty(httpPlayEntity.UrlMap[key]) {
						m3u8 = httpPlayEntity.UrlMap[key]
					}
				}
			}
		}
	}

	if IsNotEmpty(m3u8) {
		return m3u8
	}

	if len(httpPlayEntity.RequestIDs) > 0 {
		for _, reqId := range httpPlayEntity.RequestIDs {
			tempM3u8 := httpPlayEntity.UrlMap[reqId]
			if IsNotEmpty(tempM3u8) {
				m3u8 = tempM3u8
			}
		}
		if IsNotEmpty(m3u8) {
			return m3u8
		}
	}

	if len(httpPlayEntity.ExtraInfoRequestIDs) > 0 {
		for _, reqId := range httpPlayEntity.ExtraInfoRequestIDs {
			tempM3u8 := httpPlayEntity.UrlMap[reqId]
			if IsNotEmpty(tempM3u8) {
				m3u8 = tempM3u8
			}
		}
		if IsNotEmpty(m3u8) {
			return m3u8
		}
	}
	return m3u8
}
